#include "Stdafx.h"
#include "CD.h"

XCD::XCD(const XCDConfig* pConfig, XCDMgr* pMgr)
:m_pConfig(pConfig), m_pCDMgr(pMgr), m_rate(1), m_startTime(-1), m_adjustTime(0), m_finished(false)
{
}

bool XCD::Finished()
{
	if(m_finished) return true;
	Logic(time_ms());
	return m_finished;
}

float XCD::RemainTime()
{
	if(m_finished) return -1;
	float curTime = time_ms();
	Logic(curTime);
	if(m_finished) return -1;
	return m_needTime - (curTime - m_startTime);
}

bool XCD::Restart()
{
	m_startTime = time_ms();
	m_finished = false;
	m_pCDMgr->OnCDStart(this);
	return true;
}

bool XCD::Reset()
{
	m_rate = 1;
	m_adjustTime = 0;
	return Restart();
}

void XCD::Logic(float curTime)
{
	if(m_finished) return;
	if(m_startTime + m_needTime <= curTime)
	{
		m_finished = true;
		m_pCDMgr->OnCDFinished(this);
	}
}

bool XCD::Rate(float rate)
{
	float curTime = time_ms();
	Logic(curTime);
	if(m_finished)
	{
		m_rate += rate;
		m_needTime = (m_pConfig->m_needTime + m_adjustTime) / m_rate;
	}
	else
	{
		m_rate += rate;
		float remainTime = m_needTime - (curTime - m_startTime);
		float newNeedTime = (m_pConfig->m_needTime + m_adjustTime) / m_rate;
		remainTime *= newNeedTime / remainTime;
		m_needTime = newNeedTime;
		m_startTime = curTime - m_needTime + remainTime;
		m_pCDMgr->OnCDChanged(this);
	}
	return true;
}

bool XCD::AdjustTime(float adjustTime)
{
	float curTime = time_ms();
	Logic(curTime);
	if(m_finished)
	{
		m_adjustTime += adjustTime;
		m_needTime = (m_pConfig->m_needTime + m_adjustTime) / m_rate;
	}
	else
	{
		m_adjustTime += adjustTime;
		float remainTime = m_needTime - (curTime - m_startTime);
		float newNeedTime = (m_pConfig->m_needTime + m_adjustTime) / m_rate;
		remainTime *= newNeedTime / m_needTime;
		m_needTime = newNeedTime;
		m_startTime = curTime - m_needTime + remainTime;
		m_pCDMgr->OnCDChanged(this);
	}
	return true;
}

XCDMgr::XCDMgr()
{
}

XCDMgr::~XCDMgr()
{
}

bool XCDMgr::SetRate(CDType type, int id, float rate)
{
	if(type < eCDMin || type >= eCDMax) return false;
	CDMap::iterator iter = m_allCDs[type].find(id);
	if(iter != m_allCDs[type].end())
	{
		XCD* pCD = iter->second;
		return pCD->Rate(rate);
	}
	return false;
}

bool XCDMgr::SetAdjustTime(CDType type, int id, float time)
{
	if(type < eCDMin || type >= eCDMax) return false;
	CDMap::iterator iter = m_allCDs[type].find(id);
	if(iter != m_allCDs[type].end())
	{
		XCD* pCD = iter->second;
		return pCD->AdjustTime(true);
	}
	return false;
}

bool XCDMgr::Finished(CDType type, int id)
{
	if(type < eCDMin || type >= eCDMax) return true;
	CDMap::iterator iter = m_allCDs[type].find(id);
	if(iter != m_allCDs[type].end())
	{
		XCD* pCD = iter->second;
		return pCD->Finished();
	}
	return true;
}

float XCDMgr::RemainTime(CDType type, int id)
{
	if(type < eCDMin || type >= eCDMax) return -1;
	CDMap::iterator iter = m_allCDs[type].find(id);
	if(iter != m_allCDs[type].end())
	{
		XCD* pCD = iter->second;
		return pCD->RemainTime();
	}
	return -1;
}

bool XCDMgr::Restart(CDType type, int id)
{
	if(type < eCDMin || type >= eCDMax) return false;
	CDMap::iterator iter = m_allCDs[type].find(id);
	if(iter != m_allCDs[type].end())
	{
		XCD* pCD = iter->second;
		return pCD->Restart();
	}
	else
	{
		XCDConfig* pConfig = XCDConfigMgr::Get()->CDConfig(type, id);
		if(!pConfig) return false;
		XCD* pCD = new XCD(pConfig, this);
		m_allCDs[type].insert(std::make_pair(id, pCD));
		return pCD->Restart();
	}
}

bool XCDMgr::Reset(CDType type, int id)
{
	if(type < eCDMin || type >= eCDMax) return false;
	CDMap::iterator iter = m_allCDs[type].find(id);
	if(iter != m_allCDs[type].end())
	{
		XCD* pCD = iter->second;
		return pCD->Reset();
	}
	else
	{
		XCDConfig* pConfig = XCDConfigMgr::Get()->CDConfig(type, id);
		if(!pConfig) return false;
		XCD* pCD = new XCD(pConfig, this);
		m_allCDs[type].insert(std::make_pair(id, pCD));
		return pCD->Reset();
	}
	return false;
}

void XCDMgr::Logic()
{
	float curTime = time_ms();
	for(CDTypeVec::iterator typeIter = m_allCDs.begin(); typeIter != m_allCDs.end(); ++typeIter)
	{
		for(CDMap::iterator cdIter = (*typeIter).begin(); cdIter != (*typeIter).end(); ++cdIter)
		{
			cdIter->second->Logic(curTime);
		}
	}
}

void XCDMgr::OnCDFinished(XCD* pCD)
{

}

void XCDMgr::OnCDStart(XCD* pCD)
{
}

void XCDMgr::OnCDChanged(XCD* pCD)
{

}

